import serial
import minimalmodbus
import time
import threading
import sys
import struct
import csv
import os
from flask import Flask, jsonify, request, send_file
from flask_cors import CORS
from datetime import datetime

app = Flask(__name__)
CORS(app)

# 全局状态管理
class AppState:
    def __init__(self):
        self.running = False
        self.measuring = False
        self.data = []
        self.current_angle = None
        self.current_distance = None
        self.system_status = "未连接"
        self.serial_port = None
        self.stepper = None
        self.motor = None
        self.sensor_50 = None  # 50量程传感器
        self.sensor_100 = None  # 100量程传感器
        self.current_sensor = None  # 当前使用的传感器
        self.collector = None
        self.csv_file = None  # 动态生成带时间戳的文件名
        self.total_move_distance = 0
        self.lead = 5  # 步进电机导程(mm)
        self.config = {
            "port": "COM9",
            "baudrate": 115200,
            "motor_id": 0x01,
            "sensor_50_address": 3,  # 50量程传感器地址
            "sensor_100_address": 4, # 100量程传感器地址
            "stepper_id": 2,
            "repeat_times": 50,
            "stepper_cycles": 2,
            "sample_interval": 0.05,
            "measure_mode": "continuous",  # 采集模式：continuous(连续) / fixed_angle(定点)
            "angle_step": 10,  # 定点模式角度间隔(度)
            "switch_mode": "value"  # 切换模式：distance(距离) / value(测量值)
        }
        self.lock = threading.Lock()
        # 光电开关状态
        self.photo_switch = {
            "positive_limit": False,  # 正限位
            "origin": False,          # 原点
            "negative_limit": False   # 负限位
        }

state = AppState()

# 光电开关控制类（复用共享 serial.Serial，不再创建 minimalmodbus 的独立串口）
class PhotoelectricSwitchController:
    def __init__(self, serial_port, slave_address=6, lock=None):
        if serial_port is None:
            raise ValueError("必须提供共享 serial_port 实例")
        self.ser = serial_port
        self.slave = slave_address
        self.lock = lock or threading.Lock()
        self.switch_channels = {
            "positive_limit": 1,
            "origin": 2,
            "negative_limit": 3
        }
        self.input_register_base = 0x0000

    def _crc16(self, data: bytes) -> bytes:
        crc = 0xFFFF
        for b in data:
            crc ^= b
            for _ in range(8):
                if crc & 0x0001:
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return struct.pack('<H', crc)

    def _read_input_register(self, register_addr, quantity=1, timeout=1.0):
        req = bytearray()
        req.append(self.slave)
        req.append(0x04)  # FC=4 读输入寄存器（如果是离散输入/线圈要改成0x02/0x01）
        req.extend(register_addr.to_bytes(2, byteorder='big'))
        req.extend(quantity.to_bytes(2, byteorder='big'))
        req.extend(self._crc16(req))

        with self.lock:
            try:
                try:
                    self.ser.reset_input_buffer()
                    self.ser.reset_output_buffer()
                except Exception:
                    pass
                self.ser.write(req)
                self.ser.flush()
                expected_len = 5 + 2 * quantity  # slave, func, bytecount, data..., crc_lo, crc_hi
                t0 = time.time()
                resp = bytearray()
                while time.time() - t0 < timeout and len(resp) < expected_len:
                    chunk = self.ser.read(expected_len - len(resp))
                    if chunk:
                        resp.extend(chunk)
                    else:
                        time.sleep(0.01)
                if len(resp) < expected_len:
                    return None
                if resp[-2:] != self._crc16(resp[:-2]):
                    print(f"[Photo] CRC 校验失败: resp={resp.hex()}")
                    return None
                return bytes(resp)
            except Exception as e:
                print(f"[Photo] 读寄存器失败: {e}")
                return None

    def read_switch_state(self, channel):
        try:
            reg = self.input_register_base + (channel - 1)
            resp = self._read_input_register(reg, quantity=1, timeout=0.8)
            if not resp:
                return False
            # resp 格式: slave, func, bytecount, hi, lo, crc_lo, crc_hi
            hi = resp[3]
            lo = resp[4]
            val = (hi << 8) | lo
            return val == 1
        except Exception as e:
            print(f"光电开关通道{channel}读取失败: {e}")
            return False

    def update_all_switches(self):
        for switch_name, channel in self.switch_channels.items():
            state.photo_switch[switch_name] = self.read_switch_state(channel)
        return state.photo_switch

    def wait_for_switch(self, switch_name, target_state=True, timeout=30):
        start_time = time.time()
        while time.time() - start_time < timeout and state.running:
            self.update_all_switches()
            if state.photo_switch[switch_name] == target_state:
                return True
            time.sleep(0.1)
        return False

# 步进电机控制类（带光电开关闭环）
class StepperMotor:
    def __init__(self, serial_port, motor_id=2, lock=None, photo_controller=None):
        self.ser = serial_port
        self.motor_id = motor_id
        self.lock = lock or threading.Lock()
        self.photo_controller = photo_controller
        self.steps_per_mm = 200  # 每毫米步数（根据实际参数调整）

    def _calc_crc(self, data):
        crc = 0xFFFF
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x0001:
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return struct.pack('<H', crc)
    
    def _send_modbus_command(self, register, value):
        with self.lock:
            try:
                cmd = bytearray()
                cmd.append(self.motor_id)
                cmd.append(0x06)
                cmd.extend(register.to_bytes(2, byteorder='big'))
                cmd.extend(value.to_bytes(2, byteorder='big'))
                crc = self._calc_crc(cmd)
                cmd.extend(crc)
                self.ser.reset_input_buffer()
                self.ser.reset_output_buffer()
                self.ser.write(cmd)
                self.ser.flush()
                time.sleep(0.01)
                resp = self.ser.read(8)
                return len(resp) == 8
            except Exception as e:
                print(f"[Stepper] 发送命令失败: {e}")
                return False

    def move_distance(self, distance, direction):
        """移动指定距离，带光电开关限位检测"""
        steps = int(distance * self.steps_per_mm)
        if direction == 'backward':
            steps = -steps
        
        # 设置步数和方向
        if not self._send_modbus_command(0x6000, abs(steps)):
            return False
        if not self._send_modbus_command(0x6001, 1 if direction == 'forward' else 2):
            return False
        
        # 等待移动完成或限位触发
        start_time = time.time()
        while time.time() - start_time < 60:  # 超时60秒
            self.photo_controller.update_all_switches()
            if direction == 'forward' and state.photo_switch["positive_limit"]:
                print("触发正限位，停止移动")
                self.emergency_stop()
                return False
            elif direction == 'backward' and state.photo_switch["negative_limit"]:
                print("触发负限位，停止移动")
                self.emergency_stop()
                return False
            # 检查是否移动完成（假设寄存器0x6003返回当前位置）
            if self._send_modbus_command(0x6003, 0x0000):  # 读取位置指令
                time.sleep(0.1)
                # 实际应读取位置寄存器判断是否到达目标，此处简化为超时机制
            time.sleep(0.1)
        return True

    def emergency_stop(self):
        return self._send_modbus_command(0x6002, 0x0040)
    
    def close(self):
        pass

# 云台电机控制类
class HaitaiMotor:
    def __init__(self, serial_port, motor_id=0x01, lock=None):
        if serial_port is None:
            raise ValueError("必须提供共享 serial_port 实例")
        self.ser = serial_port
        self.motor_id = motor_id
        self.lock = lock or threading.Lock()
        self.counts_per_circle = 16384
        self.packet_seq = 0x00

    def _crc16_modbus(self, data):
        crc = 0xFFFF
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x0001:
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return crc & 0xFFFF

    def _pack_frame(self, cmd, data_bytes=b''):
        frame_header = [0x3E, self.packet_seq, self.motor_id, cmd, len(data_bytes)]
        frame_header_bytes = bytes(frame_header)
        crc = self._crc16_modbus(frame_header_bytes + data_bytes)
        crc_bytes = struct.pack('<H', crc)
        full_frame = frame_header_bytes + data_bytes + crc_bytes
        self.packet_seq = (self.packet_seq + 1) & 0xFF
        return full_frame

    def _send_command(self, cmd, data_bytes=b'', read_len=15, post_delay=0.1):
        full_frame = self._pack_frame(cmd, data_bytes)
        with self.lock:
            try:
                self.ser.reset_input_buffer()
                self.ser.reset_output_buffer()
                self.ser.write(full_frame)
                self.ser.flush()
                time.sleep(post_delay)
                resp = self.ser.read(read_len)
                if resp and len(resp) >= 5 and resp[0] == 0x3C:
                    return resp
                else:
                    print(f"[电机] 应答无效: 长度={len(resp) if resp else 0}, 数据={resp.hex() if resp else '无'}")
                    return None
            except Exception as e:
                print(f"[电机] 发送命令失败: {e}")
                raise

    def get_current_angle(self):
        try:
            resp = self._send_command(0x2F, b'', read_len=15, post_delay=0.1)
        except Exception as e:
            print(f"[电机] 读取角度出错: {e}")
            return None
        if resp and len(resp) == 15:
            try:
                single_turn_raw = (resp[5] | (resp[6] << 8)) & 0x3FFF
                single_turn_angle = single_turn_raw * (360.0 / self.counts_per_circle)
                multi_turn_raw = (resp[7] | (resp[8] << 8) | (resp[9] << 16) | (resp[10] << 24))
                if multi_turn_raw & 0x80000000:
                    multi_turn_raw -= 0x100000000
                multi_turn_angle = multi_turn_raw * (360.0 / self.counts_per_circle)
                return multi_turn_angle
            except Exception as e:
                print(f"[电机] 解析角度失败: {e} | 应答数据: {resp.hex()}")
                return None
        else:
            print(f"[电机] 应答长度错误（需15字节）: 实际={len(resp) if resp else 0}")
            return None

    def set_origin(self):
        print("设置当前位置为原点...")
        try:
            resp = self._send_command(0x21, b'', read_len=10, post_delay=0.5)
            if resp and len(resp) >= 10:
                result = resp[7]
                if result == 0x01:
                    print("原点设置成功")
                    return True
                else:
                    print(f"原点设置失败，结果码: 0x{result:02X}")
                    return False
            else:
                print(f"[电机] 设置原点应答无效: {resp.hex() if resp else '无响应'}")
                return False
        except Exception as e:
            print(f"[电机] 设置原点失败: {e}")
            return False

    def move_to_absolute_position(self, target_angle, max_speed=1000):
        target_counts = int(target_angle * (self.counts_per_circle / 360.0))
        target_bytes = struct.pack('<I', target_counts)
        speed_bytes = struct.pack('<H', max_speed)
        try:
            self._send_command(0x57, b'\x01' + speed_bytes, post_delay=0.2)
            time.sleep(0.1)
            self._send_command(0x55, target_bytes, post_delay=0.2)
            return True
        except Exception as e:
            print(f"[电机] 绝对值位置控制失败: {e}")
            return False

    def move_to_zero(self, timeout=300):
        print("开始回归零位...")
        if not self.set_origin():
            return False
        if not self.move_to_absolute_position(0, max_speed=500):
            return False
        start_time = time.time()
        while time.time() - start_time < timeout:
            current_angle = self.get_current_angle()
            if current_angle is not None and abs(current_angle) <= 0.1:
                print("已到达零位")
                return True
            time.sleep(0.2)
        print("回零超时")
        return False

    def rotate_360_continuous(self, timeout=300):
        """连续旋转360度并采集数据"""
        print("开始连续旋转360度...")
        if not self.move_to_absolute_position(360, max_speed=500):
            return False
        start_time = time.time()
        while time.time() - start_time < timeout and state.running:
            current_angle = self.get_current_angle()
            if current_angle is not None:
                normalized_angle = current_angle % 360
                if abs(normalized_angle - 0) <= 0.1:
                    print("已完成360度旋转")
                    return True
            time.sleep(0.2)
        print("旋转超时")
        return False

    def rotate_fixed_angle(self, angle_step, max_speed=300):
        """定点角度模式采集"""
        print(f"开始定点角度采集（间隔{angle_step}度）...")
        total_angle = 360
        current_target = 0
        success = True

        while current_target <= total_angle and state.running:
            # 移动到目标角度
            if not self.move_to_absolute_position(current_target, max_speed):
                print(f"移动到{current_target}度失败")
                success = False
                break
            
            # 稳定后采集数据
            time.sleep(1.0)
            current_angle = self.get_current_angle()
            distance = state.current_sensor.read_distance() if state.current_sensor else None
            
            if current_angle is not None and distance is not None:
                normalized_angle = current_angle % 360
                current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                with state.lock:
                    state.current_angle = normalized_angle
                    state.current_distance = distance
                    state.data.append((current_time, state.total_move_distance, normalized_angle, distance))
                print(f"定点采集 | 角度: {normalized_angle:.2f}° | 距离: {distance:.5f}mm", end='\r', flush=True)
                self._append_fixed_angle_data(current_time, state.total_move_distance, normalized_angle, distance)
            
            current_target += angle_step

        print("\n定点角度采集完成")
        return success

    def _append_fixed_angle_data(self, current_time, move_distance, angle, distance):
        """追加定点数据到CSV"""
        try:
            file_exists = os.path.isfile(state.csv_file)
            with open(state.csv_file, 'a', newline='', encoding='utf-8') as f:
                writer = csv.writer(f)
                if not file_exists:
                    writer.writerow([
                        "测量时间", "移动距离(mm)", "云台角度(°)", 
                        "距离(mm)", "传感器量程", "采集模式"
                    ])
                writer.writerow([
                    current_time, round(move_distance, 1), round(angle, 4),
                    round(distance, 5), get_current_sensor_range(), "定点"
                ])
        except Exception as e:
            print(f"数据保存失败: {e}")

    def read_status(self):
        try:
            resp = self._send_command(0x40, b'', read_len=12, post_delay=0.1)
            if resp and len(resp) >= 12:
                voltage = resp[5] * 0.2
                current = resp[6] * 0.03
                temperature = resp[7] * 0.4
                fault_code = resp[8]
                run_mode = resp[9]
                mode_map = {0: "关闭", 1: "开环", 3: "速度", 5: "位置"}
                print(f"[状态] 电压: {voltage:.1f}V, 电流: {current:.2f}A, 温度: {temperature:.1f}℃, 模式: {mode_map.get(run_mode, '未知')}")
                return True
        except Exception as e:
            print(f"[电机] 读取状态失败: {e}")
        return False

    def close_motor(self):
        try:
            self._send_command(0x50, b'', post_delay=0.2)
            print("电机已关闭")
        except Exception as e:
            print(f"[电机] 关闭失败: {e}")

    def close(self):
        self.close_motor()

# 传感器类
class LE100485Sensor:
    def __init__(self, serial_port, sensor_address, range_type, lock=None):
        self.ser = serial_port
        self.address = sensor_address
        self.range_type = range_type  # "50mm" 或 "100mm"
        self.lock = lock or threading.Lock()
    
    def read_distance(self):
        """读取距离（实际实现需根据传感器协议补充）"""
        try:
            # 示例：发送读取命令并解析（需根据传感器手册修改）
            with self.lock:
                self.ser.write(b'\x01\x03\x00\x00\x00\x02\xC4\x0B')  # 示例命令
                time.sleep(0.1)
                resp = self.ser.read(7)
            if len(resp) == 7:
                distance = struct.unpack('>f', resp[3:7])[0]  # 示例解析
                return round(distance, 5)
            return None
        except Exception as e:
            print(f"[传感器] 读取失败: {e}")
            return None
    
    def close(self):
        pass

def check_sensor_switch():
    """根据距离自动切换传感器（示例逻辑）"""
    if not state.current_sensor:
        state.current_sensor = state.sensor_50
        return
    
    distance = state.current_sensor.read_distance()
    if distance is None:
        return
    
    # 50mm传感器超量程时切换到100mm
    if state.current_sensor == state.sensor_50 and distance > 45:
        state.current_sensor = state.sensor_100
        print("切换到100mm传感器")
    # 100mm传感器在近距离时切换回50mm
    elif state.current_sensor == state.sensor_100 and distance < 40:
        state.current_sensor = state.sensor_50
        print("切换到50mm传感器")

def get_current_sensor_range():
    return state.current_sensor.range_type if state.current_sensor else "未知"

# 数据收集器类（连续模式用）
class DataCollector:
    def __init__(self, motor, sensor):
        self.running = False
        self.thread = None
        self.data = []
        self.motor = motor
        self.sensor = sensor
    
    def start(self, interval=0.05):
        if self.running:
            return
        self.data = []
        self.running = True
        self.thread = threading.Thread(target=self._collect_loop, args=(interval,), daemon=True)
        self.thread.start()
    
    def _collect_loop(self, interval):
        while self.running and state.running:
            current_angle = self.motor.get_current_angle()
            distance = self.sensor.read_distance()
            if current_angle is not None and distance is not None:
                normalized_angle = current_angle % 360
                current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                with state.lock:
                    state.current_angle = normalized_angle
                    state.current_distance = distance
                    state.data.append((current_time, state.total_move_distance, normalized_angle, distance))
                self.data.append((current_time, state.total_move_distance, normalized_angle, distance))
            time.sleep(interval)
    
    def stop(self):
        self.running = False
        if self.thread:
            self.thread.join(timeout=2)
    
    def append_to_csv(self):
        try:
            file_exists = os.path.isfile(state.csv_file)
            with open(state.csv_file, 'a', newline='', encoding='utf-8') as f:
                writer = csv.writer(f)
                if not file_exists:
                    writer.writerow([
                        "测量时间", "移动距离(mm)", "云台角度(°)", 
                        "距离(mm)", "传感器量程", "采集模式"
                    ])
                for row in self.data:
                    writer.writerow(list(row) + [get_current_sensor_range(), "连续"])
            return True
        except Exception as e:
            print(f"连续数据保存失败: {e}")
            return False

# 测量主流程
def run_measurement():
    try:
        # 初始化设备
        serial_lock = threading.Lock()
        photo_controller = PhotoelectricSwitchController(state.serial_port, slave_address=6, lock=serial_lock)
        stepper = StepperMotor(
            state.serial_port, 
            motor_id=state.config["stepper_id"], 
            lock=serial_lock, 
            photo_controller=photo_controller
        )
        motor = HaitaiMotor(
            state.serial_port, 
            motor_id=state.config["motor_id"], 
            lock=serial_lock
        )
        # 初始化传感器
        state.sensor_50 = LE100485Sensor(
            state.serial_port, 
            state.config["sensor_50_address"], 
            "50mm", 
            serial_lock
        )
        state.sensor_100 = LE100485Sensor(
            state.serial_port, 
            state.config["sensor_100_address"], 
            "100mm", 
            serial_lock
        )
        state.current_sensor = state.sensor_50  # 默认使用50mm传感器

        with state.lock:
            state.stepper = stepper
            state.motor = motor
            state.measuring = True
            state.system_status = "测量中"
            state.csv_file = f"测量数据_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"

        # 步骤1：移动到负限位
        print("移动到负限位...")
        if not stepper.move_distance(1000, 'backward'):
            with state.lock:
                state.system_status = "移动到负限位失败"
            return False
        
        # 步骤2：移动到原点
        print("移动到原点...")
        if not photo_controller.wait_for_switch("origin", timeout=60):
            with state.lock:
                state.system_status = "未检测到原点信号"
            return False
        print("已到达原点")

        # 步骤3：执行多轮测量
        for i in range(state.config["repeat_times"]):
            with state.lock:
                if not state.running:
                    break
                state.system_status = f"测量中 (第{i+1}/{state.config['repeat_times']}轮)"
            
            # 移动10mm（步进电机）
            print(f"第{i+1}轮：移动10mm...")
            if not stepper.move_distance(10, 'forward'):
                with state.lock:
                    state.system_status = f"第{i+1}轮移动失败"
                return False
            with state.lock:
                state.total_move_distance += 10  # 累计移动距离

            # 传感器切换检查
            check_sensor_switch()

            # 根据模式执行采集
            if state.config["measure_mode"] == "continuous":
                collector = DataCollector(motor, state.current_sensor)
                collector.start(interval=state.config["sample_interval"])
                if not motor.rotate_360_continuous():
                    collector.stop()
                    with state.lock:
                        state.system_status = f"第{i+1}轮旋转失败"
                    return False
                collector.stop()
                collector.append_to_csv()
            else:
                if not motor.rotate_fixed_angle(state.config["angle_step"]):
                    with state.lock:
                        state.system_status = f"第{i+1}轮定点采集失败"
                    return False

            # 每轮结束回归零位
            motor.move_to_zero()

        # 所有测量完成
        motor.close_motor()
        with state.lock:
            state.system_status = "测量完成"
            state.measuring = False
        print("所有测量任务完成！")
        return True

    except Exception as e:
        error_msg = str(e)
        with state.lock:
            state.system_status = f"测量异常: {error_msg}"
            state.measuring = False
        print(f"测量出错: {e}")
        return False
    finally:
        with state.lock:
            state.running = False

# API接口
@app.route('/api/connect', methods=['POST'])
def connect_device():
    try:
        config = request.json
        if not config:
            return jsonify({"status": "error", "message": "请提供配置参数"}), 400
        
        with state.lock:
            state.config.update(config)
            if state.serial_port and state.serial_port.is_open:
                state.serial_port.close()
            
            # 初始化串口
            state.serial_port = serial.Serial(
                port=state.config["port"],
                baudrate=state.config["baudrate"],
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                bytesize=serial.EIGHTBITS,
                timeout=1,
                write_timeout=5
            )
            
            # 启用RS485模式（如果支持）
            try:
                if hasattr(serial, "rs485"):
                    rs485_settings = serial.rs485.RS485Settings(
                        rts_level_for_tx=True,
                        rts_level_for_rx=False,
                        delay_before_tx=0.002,
                        delay_before_rx=0.002
                    )
                    state.serial_port.rs485_mode = rs485_settings
            except Exception as e:
                print(f"启用RS485失败（忽略）: {e}")
            
            state.system_status = "已连接"
        
        return jsonify({
            "status": "success",
            "message": "设备连接成功",
            "config": state.config
        })
    except serial.SerialException as e:
        msg = f"串口连接失败: {str(e)}"
        with state.lock:
            state.system_status = "连接失败"
        return jsonify({"status": "error", "message": msg}), 500
    except Exception as e:
        with state.lock:
            state.system_status = "连接失败"
        return jsonify({"status": "error", "message": f"连接异常: {str(e)}"}), 500

@app.route('/api/disconnect', methods=['POST'])
def disconnect_device():
    with state.lock:
        if state.serial_port and state.serial_port.is_open:
            state.serial_port.close()
        state.system_status = "已断开连接"
        state.running = False
        state.measuring = False
    return jsonify({"status": "success", "message": "已断开连接"})

@app.route('/api/start', methods=['POST'])
def start_measure():
    with state.lock:
        if state.system_status != "已连接":
            return jsonify({"status": "error", "message": "请先连接设备"}), 400
        if state.running:
            return jsonify({"status": "error", "message": "测量已在进行中"}), 400
        
        state.running = True
        threading.Thread(target=run_measurement, daemon=True).start()
    
    return jsonify({"status": "success", "message": "测量已启动"})

@app.route('/api/stop', methods=['POST'])
def stop_measure():
    with state.lock:
        if not state.running:
            return jsonify({"status": "error", "message": "测量未在进行中"}), 400
        state.running = False
        state.measuring = False
        state.system_status = "待机"
    return jsonify({"status": "success", "message": "测量已停止"})

@app.route('/api/emergency', methods=['POST'])
def emergency_stop():
    with state.lock:
        state.running = False
        state.measuring = False
        if state.stepper:
            state.stepper.emergency_stop()
        if state.motor:
            state.motor.close_motor()
        state.system_status = "已急停"
    return jsonify({"status": "success", "message": "已执行紧急停止"})

@app.route('/api/reset', methods=['POST'])
def reset_system():
    with state.lock:
        state.running = False
        state.measuring = False
        state.data = []
        state.current_angle = None
        state.current_distance = None
        state.total_move_distance = 0
        if state.motor:
            try:
                state.motor.move_to_zero()
            except Exception as e:
                print(f"复位失败: {e}")
        state.system_status = "待机"
    return jsonify({"status": "success", "message": "系统已复位"})

@app.route('/api/status', methods=['GET'])
def get_status():
    with state.lock:
        return jsonify({
            "system_status": state.system_status,
            "measuring": state.measuring,
            "current_angle": round(state.current_angle, 4) if state.current_angle else None,
            "current_distance": round(state.current_distance, 5) if state.current_distance else None,
            "total_move_distance": round(state.total_move_distance, 1),
            "data_count": len(state.data),
            "photo_switch": state.photo_switch,
            "current_sensor_range": get_current_sensor_range()
        })

@app.route('/api/config', methods=['GET'])
def get_config():
    with state.lock:
        return jsonify({"status": "success", "config": state.config})

@app.route('/api/set-mode', methods=['POST'])
def set_measure_mode():
    try:
        data = request.json
        if "measure_mode" not in data:
            return jsonify({"status": "error", "message": "请指定采集模式"}), 400
        
        with state.lock:
            state.config["measure_mode"] = data["measure_mode"]
            if data["measure_mode"] == "fixed_angle":
                if "angle_step" not in data or not (1 <= data["angle_step"] <= 180):
                    return jsonify({"status": "error", "message": "角度间隔必须为1-180之间的整数"}), 400
                state.config["angle_step"] = data["angle_step"]
        
        return jsonify({
            "status": "success",
            "message": f"已设置为{data['measure_mode']}模式",
            "config": {
                "measure_mode": state.config["measure_mode"],
                "angle_step": state.config["angle_step"]
            }
        })
    except Exception as e:
        return jsonify({"status": "error", "message": f"设置失败: {str(e)}"}), 500

@app.route('/api/download-data', methods=['GET'])
def download_data():
    with state.lock:
        if not state.csv_file or not os.path.exists(state.csv_file):
            return jsonify({"status": "error", "message": "无数据文件"}), 404
        return send_file(state.csv_file, as_attachment=True)

if __name__ == '__main__':
    print("=== 激光位移测量系统 ===")
    print(f"启动时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"API服务地址: http://0.0.0.0:5000")
    app.run(host='0.0.0.0', port=5000, debug=False, use_reloader=False)